<!DOCTYPE html>



  


<html class="theme-next pisces use-motion" lang="zh-CN">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.3" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png?v=5.1.3">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.png?v=5.1.3">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png?v=5.1.3">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.3" color="#222">





  <meta name="keywords" content="python," />




  


  <link rel="alternate" href="/atom.xml" title="理想-咸鱼" type="application/atom+xml" />






<meta name="description" content="iostream.pyA utility class to write to and read from a non-blocking socket. IOStream 对 socket 进行包装，采用注册回调方式实现非阻塞。通过接口注册各个事件回调  _read_callback _write_callback _close_callback _connect_callback  ioloop">
<meta property="og:type" content="article">
<meta property="og:title" content="tornado源码之iostream">
<meta property="og:url" content="http://yoursite.com/2018/12/20/tornado-yuan-ma-zhi-iostream/index.html">
<meta property="og:site_name" content="理想-咸鱼">
<meta property="og:description" content="iostream.pyA utility class to write to and read from a non-blocking socket. IOStream 对 socket 进行包装，采用注册回调方式实现非阻塞。通过接口注册各个事件回调  _read_callback _write_callback _close_callback _connect_callback  ioloop">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2018-12-20T08:46:51.000Z">
<meta property="article:modified_time" content="2018-12-20T08:46:51.000Z">
<meta property="article:author" content="bigfish">
<meta property="article:tag" content="python">
<meta name="twitter:card" content="summary">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    version: '5.1.3',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: 'Author'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://yoursite.com/2018/12/20/tornado-yuan-ma-zhi-iostream/"/>





  <title>tornado源码之iostream | 理想-咸鱼</title>
  








<meta name="generator" content="Hexo 4.2.0"></head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-CN">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">理想-咸鱼</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">鱼翔浅底</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            Home
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            Archives
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            Tags
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            Categories
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/12/20/tornado-yuan-ma-zhi-iostream/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">tornado源码之iostream</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-12-20T16:46:51+08:00">
                2018-12-20
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          
            <span class="post-meta-divider">|</span>
            <span class="page-pv"><i class="fa fa-file-o"></i>  阅读数
            <span class="busuanzi-value" id="busuanzi_value_page_pv" ></span>
            </span>
          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  2.8k
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  15
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <h1 id="iostream-py"><a href="#iostream-py" class="headerlink" title="iostream.py"></a>iostream.py</h1><p>A utility class to write to and read from a non-blocking socket.</p>
<p>IOStream 对 socket 进行包装，采用注册回调方式实现非阻塞。<br>通过接口注册各个事件回调</p>
<ul>
<li>_read_callback</li>
<li>_write_callback</li>
<li>_close_callback</li>
<li>_connect_callback</li>
</ul>
<p>ioloop 中 socket 事件发生后，调用 IOStream._handle_events 方法，对事件进行分发。<br>对应的事件处理过程中，如果满足注册的回调条件，则调用回调函数<br>回调函数在 IOStream._handle_events 中被调用</p>
<h2 id="contents"><a href="#contents" class="headerlink" title="contents"></a>contents</h2><ul>
<li><a href="#iostreampy">iostream.py</a><ul>
<li><a href="#contents">contents</a></li>
<li><a href="#example">example</a></li>
<li><a href="#head">head</a></li>
<li><a href="#iostreaminit">IOStream.__init__</a></li>
<li><a href="#iostreamconnect">IOStream.connect</a></li>
<li><a href="#iostreamreaduntil">IOStream.read_until</a></li>
<li><a href="#iostreamreadbytes">IOStream.read_bytes</a></li>
<li><a href="#iostreamwrite">IOStream.write</a></li>
<li><a href="#iostreamclose">IOStream.close</a></li>
<li><a href="#iostreamhandleevents">IOStream._handle_events</a></li>
<li><a href="#iostreamruncallback">IOStream._run_callback</a></li>
<li><a href="#iostreamruncallback-1">IOStream._run_callback</a></li>
<li><a href="#iostreamreadfromsocket">IOStream._read_from_socket</a></li>
<li><a href="#iostreamreadtobuffer">IOStream._read_to_buffer</a></li>
<li><a href="#iostreamreadfrombuffer">IOStream._read_from_buffer</a></li>
<li><a href="#iostreamhandleconnect">IOStream._handle_connect</a></li>
<li><a href="#iostreamhandlewrite">IOStream._handle_write</a></li>
<li><a href="#iostreamconsume">IOStream._consume</a></li>
<li><a href="#iostreamaddiostate">IOStream._add_io_state</a></li>
<li><a href="#iostreamreadbuffersize">IOStream._read_buffer_size</a></li>
<li><a href="#copyright">copyright</a></li>
</ul>
</li>
</ul>
<h2 id="example"><a href="#example" class="headerlink" title="example"></a>example</h2><p>一个简单的 IOStream 客户端示例<br><strong>由此可见， IOStream 是一个异步回调链</strong></p>
<ol>
<li>创建 socket</li>
<li>创建 IOStream 对象</li>
<li>连接到主机，传入连接成功后回调函数 send_request</li>
<li>socket 输出数据请求页面，读取 head, 传入读取 head 成功后回调函数 on_headers</li>
<li>继续读取 body, 传入读取 body 成功后回调函数 on_body</li>
<li>关闭 stream，关闭 ioloop</li>
</ol>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> tornado <span class="keyword">import</span> ioloop</span><br><span class="line"><span class="keyword">from</span> tornado <span class="keyword">import</span> iostream</span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">send_request</span><span class="params">()</span>:</span></span><br><span class="line">    stream.write(<span class="string">"GET / HTTP/1.0\r\nHost: baidu.com\r\n\r\n"</span>)</span><br><span class="line">    stream.read_until(<span class="string">"\r\n\r\n"</span>, on_headers)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">on_headers</span><span class="params">(data)</span>:</span></span><br><span class="line">    headers = &#123;&#125;</span><br><span class="line">    <span class="keyword">for</span> line <span class="keyword">in</span> data.split(<span class="string">"\r\n"</span>):</span><br><span class="line">        parts = line.split(<span class="string">":"</span>)</span><br><span class="line">        <span class="keyword">if</span> len(parts) == <span class="number">2</span>:</span><br><span class="line">            headers[parts[<span class="number">0</span>].strip()] = parts[<span class="number">1</span>].strip()</span><br><span class="line">    stream.read_bytes(int(headers[<span class="string">"Content-Length"</span>]), on_body)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">on_body</span><span class="params">(data)</span>:</span></span><br><span class="line">    <span class="keyword">print</span> data</span><br><span class="line">    stream.close()</span><br><span class="line">    ioloop.IOLoop.instance().stop()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, <span class="number">0</span>)</span><br><span class="line">stream = iostream.IOStream(s)</span><br><span class="line">stream.connect((<span class="string">"baidu.com"</span>, <span class="number">80</span>), send_request)</span><br><span class="line">ioloop.IOLoop.instance().start()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># html&gt;</span></span><br><span class="line"><span class="comment"># &lt;meta http-equiv="refresh" content="0;        url=http://www.baidu.com/"&gt;</span></span><br><span class="line"><span class="comment"># &lt;/html&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="head"><a href="#head" class="headerlink" title="head"></a>head</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> __future__ <span class="keyword">import</span> with_statement</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> collections</span><br><span class="line"><span class="keyword">import</span> errno</span><br><span class="line"><span class="keyword">import</span> logging</span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> tornado <span class="keyword">import</span> ioloop</span><br><span class="line"><span class="keyword">from</span> tornado <span class="keyword">import</span> stack_context</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">    <span class="keyword">import</span> ssl <span class="comment"># Python 2.6+</span></span><br><span class="line"><span class="keyword">except</span> ImportError:</span><br><span class="line">    ssl = <span class="literal">None</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-init"><a href="#IOStream-init" class="headerlink" title="IOStream.__init__"></a>IOStream.__init__</h2><p>包装 socket 类<br>关键语句 <code>self.io_loop.add_handler(self.socket.fileno(), self._handle_events, self._state)</code> 将自身的_handle_events 加入到全局 ioloop poll 事件回调<br>此时只注册了 ERROR 类型事件</p>
<p>_read_buffer: 读缓冲</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IOStream</span><span class="params">(object)</span>:</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, socket, io_loop=None, max_buffer_size=<span class="number">104857600</span>,</span></span></span><br><span class="line"><span class="function"><span class="params">                 read_chunk_size=<span class="number">4096</span>)</span>:</span></span><br><span class="line">        self.socket = socket</span><br><span class="line">        self.socket.setblocking(<span class="literal">False</span>)</span><br><span class="line">        self.io_loop = io_loop <span class="keyword">or</span> ioloop.IOLoop.instance()</span><br><span class="line">        self.max_buffer_size = max_buffer_size</span><br><span class="line">        self.read_chunk_size = read_chunk_size</span><br><span class="line">        self._read_buffer = collections.deque()</span><br><span class="line">        self._write_buffer = collections.deque()</span><br><span class="line">        self._write_buffer_frozen = <span class="literal">False</span></span><br><span class="line">        self._read_delimiter = <span class="literal">None</span></span><br><span class="line">        self._read_bytes = <span class="literal">None</span></span><br><span class="line">        self._read_callback = <span class="literal">None</span></span><br><span class="line">        self._write_callback = <span class="literal">None</span></span><br><span class="line">        self._close_callback = <span class="literal">None</span></span><br><span class="line">        self._connect_callback = <span class="literal">None</span></span><br><span class="line">        self._connecting = <span class="literal">False</span></span><br><span class="line">        self._state = self.io_loop.ERROR</span><br><span class="line">        <span class="keyword">with</span> stack_context.NullContext():</span><br><span class="line">            self.io_loop.add_handler(</span><br><span class="line">                self.socket.fileno(), self._handle_events, self._state)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-connect"><a href="#IOStream-connect" class="headerlink" title="IOStream.connect"></a>IOStream.connect</h2><p>连接 socket 到远程地址，非阻塞模式</p>
<ol>
<li>连接 socket</li>
<li>注册连接完成回调</li>
<li>poll 增加 socket 写事件</li>
</ol>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">connect</span><span class="params">(self, address, callback=None)</span>:</span></span><br><span class="line">    <span class="string">"""Connects the socket to a remote address without blocking.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    May only be called if the socket passed to the constructor was</span></span><br><span class="line"><span class="string">    not previously connected.  The address parameter is in the</span></span><br><span class="line"><span class="string">    same format as for socket.connect, i.e. a (host, port) tuple.</span></span><br><span class="line"><span class="string">    If callback is specified, it will be called when the</span></span><br><span class="line"><span class="string">    connection is completed.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Note that it is safe to call IOStream.write while the</span></span><br><span class="line"><span class="string">    connection is pending, in which case the data will be written</span></span><br><span class="line"><span class="string">    as soon as the connection is ready.  Calling IOStream read</span></span><br><span class="line"><span class="string">    methods before the socket is connected works on some platforms</span></span><br><span class="line"><span class="string">    but is non-portable.</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    self._connecting = <span class="literal">True</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        self.socket.connect(address)</span><br><span class="line">    <span class="keyword">except</span> socket.error, e:</span><br><span class="line">        <span class="comment"># In non-blocking mode connect() always raises an exception</span></span><br><span class="line">        <span class="keyword">if</span> e.args[<span class="number">0</span>] <span class="keyword">not</span> <span class="keyword">in</span> (errno.EINPROGRESS, errno.EWOULDBLOCK):</span><br><span class="line">            <span class="keyword">raise</span></span><br><span class="line">    self._connect_callback = stack_context.wrap(callback)</span><br><span class="line">    self._add_io_state(self.io_loop.WRITE)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-read-until"><a href="#IOStream-read-until" class="headerlink" title="IOStream.read_until"></a>IOStream.read_until</h2><ol>
<li>注册读完成回调</li>
<li>尝试从缓冲中读</li>
<li>从 socket 中读到缓冲区</li>
<li>重复 2,3, 没有数据则退出</li>
<li>将 socket 读事件加入 poll</li>
</ol>
<p>如果缓存中数据满足条件，则直接执行 callback 并返回，<br>否则，保存 callback 函数下次 read 事件发生时，_handle_events 处理读事件时，再进行检测及调用</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">read_until</span><span class="params">(self, delimiter, callback)</span>:</span></span><br><span class="line">    <span class="string">"""Call callback when we read the given delimiter."""</span></span><br><span class="line">    <span class="keyword">assert</span> <span class="keyword">not</span> self._read_callback, <span class="string">"Already reading"</span></span><br><span class="line">    self._read_delimiter = delimiter</span><br><span class="line">    self._read_callback = stack_context.wrap(callback)</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        <span class="comment"># See if we've already got the data from a previous read</span></span><br><span class="line">        <span class="keyword">if</span> self._read_from_buffer():</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        self._check_closed()</span><br><span class="line">        <span class="keyword">if</span> self._read_to_buffer() == <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">    self._add_io_state(self.io_loop.READ)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-read-bytes"><a href="#IOStream-read-bytes" class="headerlink" title="IOStream.read_bytes"></a>IOStream.read_bytes</h2><p>参考 read_until，读限定字节</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">read_bytes</span><span class="params">(self, num_bytes, callback)</span>:</span></span><br><span class="line">    <span class="string">"""Call callback when we read the given number of bytes."""</span></span><br><span class="line">    <span class="keyword">assert</span> <span class="keyword">not</span> self._read_callback, <span class="string">"Already reading"</span></span><br><span class="line">    <span class="keyword">if</span> num_bytes == <span class="number">0</span>:</span><br><span class="line">        callback(<span class="string">""</span>)</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    self._read_bytes = num_bytes</span><br><span class="line">    self._read_callback = stack_context.wrap(callback)</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        <span class="keyword">if</span> self._read_from_buffer():</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        self._check_closed()</span><br><span class="line">        <span class="keyword">if</span> self._read_to_buffer() == <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">    self._add_io_state(self.io_loop.READ)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-write"><a href="#IOStream-write" class="headerlink" title="IOStream.write"></a>IOStream.write</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">write</span><span class="params">(self, data, callback=None)</span>:</span></span><br><span class="line">    <span class="string">"""Write the given data to this stream.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    If callback is given, we call it when all of the buffered write</span></span><br><span class="line"><span class="string">    data has been successfully written to the stream. If there was</span></span><br><span class="line"><span class="string">    previously buffered write data and an old write callback, that</span></span><br><span class="line"><span class="string">    callback is simply overwritten with this new callback.</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    self._check_closed()</span><br><span class="line">    self._write_buffer.append(data)</span><br><span class="line">    self._add_io_state(self.io_loop.WRITE)</span><br><span class="line">    self._write_callback = stack_context.wrap(callback)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">set_close_callback</span><span class="params">(self, callback)</span>:</span></span><br><span class="line">    <span class="string">"""Call the given callback when the stream is closed."""</span></span><br><span class="line">    self._close_callback = stack_context.wrap(callback)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-close"><a href="#IOStream-close" class="headerlink" title="IOStream.close"></a>IOStream.close</h2><ol>
<li>从 ioloop 移除 socket 事件</li>
<li>关闭 socket</li>
<li>调用关闭回调</li>
</ol>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">close</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="string">"""Close this stream."""</span></span><br><span class="line">    <span class="keyword">if</span> self.socket <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">        self.io_loop.remove_handler(self.socket.fileno())</span><br><span class="line">        self.socket.close()</span><br><span class="line">        self.socket = <span class="literal">None</span></span><br><span class="line">        <span class="keyword">if</span> self._close_callback:</span><br><span class="line">            self._run_callback(self._close_callback)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">reading</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="string">"""Returns true if we are currently reading from the stream."""</span></span><br><span class="line">    <span class="keyword">return</span> self._read_callback <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">writing</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="string">"""Returns true if we are currently writing to the stream."""</span></span><br><span class="line">    <span class="keyword">return</span> bool(self._write_buffer)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">closed</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="keyword">return</span> self.socket <span class="keyword">is</span> <span class="literal">None</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-handle-events"><a href="#IOStream-handle-events" class="headerlink" title="IOStream._handle_events"></a>IOStream._handle_events</h2><p>核心回调<br>任何类型的 socket 事件触发 ioloop 回调_handle_events，然后在_handle_events 再进行分发<br>值得注意的是，IOStream 不处理连接请求的 read 事件<br><strong>注意</strong><br>作为服务端，默认代理的是已经建立连接的 socket</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># HTTPServer.\_handle_events</span></span><br><span class="line"><span class="comment"># connection 为已经accept的连接</span></span><br><span class="line">stream = iostream.IOStream(connection, io_loop=self.io_loop)</span><br></pre></td></tr></table></figure>

<p>作为客户端，需要手动调用 IOStream.connect，连接成功后，成功回调在 write 事件中处理</p>
<p>这个实现比较别扭</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_handle_events</span><span class="params">(self, fd, events)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> self.socket:</span><br><span class="line">        logging.warning(<span class="string">"Got events for closed stream %d"</span>, fd)</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="comment"># 处理读事件，调用已注册回调</span></span><br><span class="line">        <span class="keyword">if</span> events &amp; self.io_loop.READ:</span><br><span class="line">            self._handle_read()</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> self.socket:</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        <span class="comment"># 处理写事件，如果是刚建立连接，调用连接建立回调</span></span><br><span class="line">        <span class="keyword">if</span> events &amp; self.io_loop.WRITE:</span><br><span class="line">            <span class="keyword">if</span> self._connecting:</span><br><span class="line">                self._handle_connect()</span><br><span class="line">            self._handle_write()</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> self.socket:</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        <span class="comment"># 错误事件，关闭 socket</span></span><br><span class="line">        <span class="keyword">if</span> events &amp; self.io_loop.ERROR:</span><br><span class="line">            self.close()</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        state = self.io_loop.ERROR</span><br><span class="line">        <span class="keyword">if</span> self.reading():</span><br><span class="line">            state |= self.io_loop.READ</span><br><span class="line">        <span class="keyword">if</span> self.writing():</span><br><span class="line">            state |= self.io_loop.WRITE</span><br><span class="line">        <span class="keyword">if</span> state != self._state:</span><br><span class="line">            self._state = state</span><br><span class="line">            self.io_loop.update_handler(self.socket.fileno(), self._state)</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        logging.error(<span class="string">"Uncaught exception, closing connection."</span>,</span><br><span class="line">                      exc_info=<span class="literal">True</span>)</span><br><span class="line">        self.close()</span><br><span class="line">        <span class="keyword">raise</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-run-callback"><a href="#IOStream-run-callback" class="headerlink" title="IOStream._run_callback"></a>IOStream._run_callback</h2><p>执行回调</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_run_callback</span><span class="params">(self, callback, *args, **kwargs)</span>:</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="comment"># Use a NullContext to ensure that all StackContexts are run</span></span><br><span class="line">        <span class="comment"># inside our blanket exception handler rather than outside.</span></span><br><span class="line">        <span class="keyword">with</span> stack_context.NullContext():</span><br><span class="line">            callback(*args, **kwargs)</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        logging.error(<span class="string">"Uncaught exception, closing connection."</span>,</span><br><span class="line">                      exc_info=<span class="literal">True</span>)</span><br><span class="line">        <span class="comment"># Close the socket on an uncaught exception from a user callback</span></span><br><span class="line">        <span class="comment"># (It would eventually get closed when the socket object is</span></span><br><span class="line">        <span class="comment"># gc'd, but we don't want to rely on gc happening before we</span></span><br><span class="line">        <span class="comment"># run out of file descriptors)</span></span><br><span class="line">        self.close()</span><br><span class="line">        <span class="comment"># Re-raise the exception so that IOLoop.handle_callback_exception</span></span><br><span class="line">        <span class="comment"># can see it and log the error</span></span><br><span class="line">        <span class="keyword">raise</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-run-callback-1"><a href="#IOStream-run-callback-1" class="headerlink" title="IOStream._run_callback"></a>IOStream._run_callback</h2><p>读回调</p>
<ol>
<li>从 socket 读取数据到缓存</li>
<li>无数据, socket 关闭</li>
<li>检测是否满足 read_until read_bytes</li>
<li>满足则执行对应回调</li>
</ol>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_handle_read</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="comment"># Read from the socket until we get EWOULDBLOCK or equivalent.</span></span><br><span class="line">            <span class="comment"># SSL sockets do some internal buffering, and if the data is</span></span><br><span class="line">            <span class="comment"># sitting in the SSL object's buffer select() and friends</span></span><br><span class="line">            <span class="comment"># can't see it; the only way to find out if it's there is to</span></span><br><span class="line">            <span class="comment"># try to read it.</span></span><br><span class="line">            result = self._read_to_buffer()</span><br><span class="line">        <span class="keyword">except</span> Exception:</span><br><span class="line">            self.close()</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        <span class="keyword">if</span> result == <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="keyword">if</span> self._read_from_buffer():</span><br><span class="line">                <span class="keyword">return</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-read-from-socket"><a href="#IOStream-read-from-socket" class="headerlink" title="IOStream._read_from_socket"></a>IOStream._read_from_socket</h2><p>从 socket 读取数据</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_read_from_socket</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="string">"""Attempts to read from the socket.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Returns the data read or None if there is nothing to read.</span></span><br><span class="line"><span class="string">    May be overridden in subclasses.</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        chunk = self.socket.recv(self.read_chunk_size)</span><br><span class="line">    <span class="keyword">except</span> socket.error, e:</span><br><span class="line">        <span class="keyword">if</span> e.args[<span class="number">0</span>] <span class="keyword">in</span> (errno.EWOULDBLOCK, errno.EAGAIN):</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="keyword">raise</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> chunk:</span><br><span class="line">        self.close()</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">    <span class="keyword">return</span> chunk</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-read-to-buffer"><a href="#IOStream-read-to-buffer" class="headerlink" title="IOStream._read_to_buffer"></a>IOStream._read_to_buffer</h2><p>从 socket 读取数据存入缓存</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_read_to_buffer</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="string">"""Reads from the socket and appends the result to the read buffer.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Returns the number of bytes read.  Returns 0 if there is nothing</span></span><br><span class="line"><span class="string">    to read (i.e. the read returns EWOULDBLOCK or equivalent).  On</span></span><br><span class="line"><span class="string">    error closes the socket and raises an exception.</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        chunk = self._read_from_socket()</span><br><span class="line">    <span class="keyword">except</span> socket.error, e:</span><br><span class="line">        <span class="comment"># ssl.SSLError is a subclass of socket.error</span></span><br><span class="line">        logging.warning(<span class="string">"Read error on %d: %s"</span>,</span><br><span class="line">                        self.socket.fileno(), e)</span><br><span class="line">        self.close()</span><br><span class="line">        <span class="keyword">raise</span></span><br><span class="line">    <span class="keyword">if</span> chunk <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">    self._read_buffer.append(chunk)</span><br><span class="line">    <span class="keyword">if</span> self._read_buffer_size() &gt;= self.max_buffer_size:</span><br><span class="line">        logging.error(<span class="string">"Reached maximum read buffer size"</span>)</span><br><span class="line">        self.close()</span><br><span class="line">        <span class="keyword">raise</span> IOError(<span class="string">"Reached maximum read buffer size"</span>)</span><br><span class="line">    <span class="keyword">return</span> len(chunk)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-read-from-buffer"><a href="#IOStream-read-from-buffer" class="headerlink" title="IOStream._read_from_buffer"></a>IOStream._read_from_buffer</h2><p>从缓冲中过滤数据<br>检测是否满足结束条件 (read_until/read_bytes)，满足则调用之前注册的回调<br>采用的是查询方式</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_read_from_buffer</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="string">"""Attempts to complete the currently-pending read from the buffer.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Returns True if the read was completed.</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    <span class="keyword">if</span> self._read_bytes:</span><br><span class="line">        <span class="keyword">if</span> self._read_buffer_size() &gt;= self._read_bytes:</span><br><span class="line">            num_bytes = self._read_bytes</span><br><span class="line">            callback = self._read_callback</span><br><span class="line">            self._read_callback = <span class="literal">None</span></span><br><span class="line">            self._read_bytes = <span class="literal">None</span></span><br><span class="line">            self._run_callback(callback, self._consume(num_bytes))</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line">    <span class="keyword">elif</span> self._read_delimiter:</span><br><span class="line">        _merge_prefix(self._read_buffer, sys.maxint)</span><br><span class="line">        loc = self._read_buffer[<span class="number">0</span>].find(self._read_delimiter)</span><br><span class="line">        <span class="keyword">if</span> loc != <span class="number">-1</span>:</span><br><span class="line">            callback = self._read_callback</span><br><span class="line">            delimiter_len = len(self._read_delimiter)</span><br><span class="line">            self._read_callback = <span class="literal">None</span></span><br><span class="line">            self._read_delimiter = <span class="literal">None</span></span><br><span class="line">            self._run_callback(callback,</span><br><span class="line">                               self._consume(loc + delimiter_len))</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">False</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-handle-connect"><a href="#IOStream-handle-connect" class="headerlink" title="IOStream._handle_connect"></a>IOStream._handle_connect</h2><p>调用连接建立回调，并清除连接中标志</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_handle_connect</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> self._connect_callback <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">        callback = self._connect_callback</span><br><span class="line">        self._connect_callback = <span class="literal">None</span></span><br><span class="line">        self._run_callback(callback)</span><br><span class="line">    self._connecting = <span class="literal">False</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-handle-write"><a href="#IOStream-handle-write" class="headerlink" title="IOStream._handle_write"></a>IOStream._handle_write</h2><p>写事件</p>
<ol>
<li>从缓冲区获取限定范围内数据</li>
<li>调用 socket.send 输出数据</li>
<li>如果数据发送我且已注册回调，调用发送完成回调</li>
</ol>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_handle_write</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="keyword">while</span> self._write_buffer:</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="keyword">if</span> <span class="keyword">not</span> self._write_buffer_frozen:</span><br><span class="line">                <span class="comment"># On windows, socket.send blows up if given a</span></span><br><span class="line">                <span class="comment"># write buffer that's too large, instead of just</span></span><br><span class="line">                <span class="comment"># returning the number of bytes it was able to</span></span><br><span class="line">                <span class="comment"># process.  Therefore we must not call socket.send</span></span><br><span class="line">                <span class="comment"># with more than 128KB at a time.</span></span><br><span class="line">                _merge_prefix(self._write_buffer, <span class="number">128</span> * <span class="number">1024</span>)</span><br><span class="line">            num_bytes = self.socket.send(self._write_buffer[<span class="number">0</span>])</span><br><span class="line">            self._write_buffer_frozen = <span class="literal">False</span></span><br><span class="line">            _merge_prefix(self._write_buffer, num_bytes)</span><br><span class="line">            self._write_buffer.popleft()</span><br><span class="line">        <span class="keyword">except</span> socket.error, e:</span><br><span class="line">            <span class="keyword">if</span> e.args[<span class="number">0</span>] <span class="keyword">in</span> (errno.EWOULDBLOCK, errno.EAGAIN):</span><br><span class="line">                <span class="comment"># With OpenSSL, after send returns EWOULDBLOCK,</span></span><br><span class="line">                <span class="comment"># the very same string object must be used on the</span></span><br><span class="line">                <span class="comment"># next call to send.  Therefore we suppress</span></span><br><span class="line">                <span class="comment"># merging the write buffer after an EWOULDBLOCK.</span></span><br><span class="line">                <span class="comment"># A cleaner solution would be to set</span></span><br><span class="line">                <span class="comment"># SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER, but this is</span></span><br><span class="line">                <span class="comment"># not yet accessible from python</span></span><br><span class="line">                <span class="comment"># (http://bugs.python.org/issue8240)</span></span><br><span class="line">                self._write_buffer_frozen = <span class="literal">True</span></span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                logging.warning(<span class="string">"Write error on %d: %s"</span>,</span><br><span class="line">                                self.socket.fileno(), e)</span><br><span class="line">                self.close()</span><br><span class="line">                <span class="keyword">return</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> self._write_buffer <span class="keyword">and</span> self._write_callback:</span><br><span class="line">        callback = self._write_callback</span><br><span class="line">        self._write_callback = <span class="literal">None</span></span><br><span class="line">        self._run_callback(callback)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-consume"><a href="#IOStream-consume" class="headerlink" title="IOStream._consume"></a>IOStream._consume</h2><p>从读缓存消费 loc 长度的数据</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_consume</span><span class="params">(self, loc)</span>:</span></span><br><span class="line">    _merge_prefix(self._read_buffer, loc)</span><br><span class="line">    <span class="keyword">return</span> self._read_buffer.popleft()</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_check_closed</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> self.socket:</span><br><span class="line">        <span class="keyword">raise</span> IOError(<span class="string">"Stream is closed"</span>)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-add-io-state"><a href="#IOStream-add-io-state" class="headerlink" title="IOStream._add_io_state"></a>IOStream._add_io_state</h2><p>增加 socket 事件状态</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_add_io_state</span><span class="params">(self, state)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> self.socket <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="comment"># connection has been closed, so there can be no future events</span></span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> self._state &amp; state:</span><br><span class="line">        self._state = self._state | state</span><br><span class="line">        self.io_loop.update_handler(self.socket.fileno(), self._state)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-read-buffer-size"><a href="#IOStream-read-buffer-size" class="headerlink" title="IOStream._read_buffer_size"></a>IOStream._read_buffer_size</h2><p>获取读缓存中已有数据长度</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br></pre></td><td class="code"><pre><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_read_buffer_size</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> sum(len(chunk) <span class="keyword">for</span> chunk <span class="keyword">in</span> self._read_buffer)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SSLIOStream</span><span class="params">(IOStream)</span>:</span></span><br><span class="line">    <span class="string">"""A utility class to write to and read from a non-blocking socket.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    If the socket passed to the constructor is already connected,</span></span><br><span class="line"><span class="string">    it should be wrapped with</span></span><br><span class="line"><span class="string">        ssl.wrap_socket(sock, do_handshake_on_connect=False, **kwargs)</span></span><br><span class="line"><span class="string">    before constructing the SSLIOStream.  Unconnected sockets will be</span></span><br><span class="line"><span class="string">    wrapped when IOStream.connect is finished.</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, *args, **kwargs)</span>:</span></span><br><span class="line">        <span class="string">"""Creates an SSLIOStream.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        If a dictionary is provided as keyword argument ssl_options,</span></span><br><span class="line"><span class="string">        it will be used as additional keyword arguments to ssl.wrap_socket.</span></span><br><span class="line"><span class="string">        """</span></span><br><span class="line">        self._ssl_options = kwargs.pop(<span class="string">'ssl_options'</span>, &#123;&#125;)</span><br><span class="line">        super(SSLIOStream, self).__init__(*args, **kwargs)</span><br><span class="line">        self._ssl_accepting = <span class="literal">True</span></span><br><span class="line">        self._handshake_reading = <span class="literal">False</span></span><br><span class="line">        self._handshake_writing = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">reading</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self._handshake_reading <span class="keyword">or</span> super(SSLIOStream, self).reading()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">writing</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self._handshake_writing <span class="keyword">or</span> super(SSLIOStream, self).writing()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_do_ssl_handshake</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="comment"># Based on code from test_ssl.py in the python stdlib</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            self._handshake_reading = <span class="literal">False</span></span><br><span class="line">            self._handshake_writing = <span class="literal">False</span></span><br><span class="line">            self.socket.do_handshake()</span><br><span class="line">        <span class="keyword">except</span> ssl.SSLError, err:</span><br><span class="line">            <span class="keyword">if</span> err.args[<span class="number">0</span>] == ssl.SSL_ERROR_WANT_READ:</span><br><span class="line">                self._handshake_reading = <span class="literal">True</span></span><br><span class="line">                <span class="keyword">return</span></span><br><span class="line">            <span class="keyword">elif</span> err.args[<span class="number">0</span>] == ssl.SSL_ERROR_WANT_WRITE:</span><br><span class="line">                self._handshake_writing = <span class="literal">True</span></span><br><span class="line">                <span class="keyword">return</span></span><br><span class="line">            <span class="keyword">elif</span> err.args[<span class="number">0</span>] <span class="keyword">in</span> (ssl.SSL_ERROR_EOF,</span><br><span class="line">                                 ssl.SSL_ERROR_ZERO_RETURN):</span><br><span class="line">                <span class="keyword">return</span> self.close()</span><br><span class="line">            <span class="keyword">elif</span> err.args[<span class="number">0</span>] == ssl.SSL_ERROR_SSL:</span><br><span class="line">                logging.warning(<span class="string">"SSL Error on %d: %s"</span>, self.socket.fileno(), err)</span><br><span class="line">                <span class="keyword">return</span> self.close()</span><br><span class="line">            <span class="keyword">raise</span></span><br><span class="line">        <span class="keyword">except</span> socket.error, err:</span><br><span class="line">            <span class="keyword">if</span> err.args[<span class="number">0</span>] == errno.ECONNABORTED:</span><br><span class="line">                <span class="keyword">return</span> self.close()</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            self._ssl_accepting = <span class="literal">False</span></span><br><span class="line">            super(SSLIOStream, self)._handle_connect()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_handle_read</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> self._ssl_accepting:</span><br><span class="line">            self._do_ssl_handshake()</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        super(SSLIOStream, self)._handle_read()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_handle_write</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> self._ssl_accepting:</span><br><span class="line">            self._do_ssl_handshake()</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        super(SSLIOStream, self)._handle_write()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_handle_connect</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.socket = ssl.wrap_socket(self.socket,</span><br><span class="line">                                      do_handshake_on_connect=<span class="literal">False</span>,</span><br><span class="line">                                      **self._ssl_options)</span><br><span class="line">        <span class="comment"># Don't call the superclass's _handle_connect (which is responsible</span></span><br><span class="line">        <span class="comment"># for telling the application that the connection is complete)</span></span><br><span class="line">        <span class="comment"># until we've completed the SSL handshake (so certificates are</span></span><br><span class="line">        <span class="comment"># available, etc).</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_read_from_socket</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="comment"># SSLSocket objects have both a read() and recv() method,</span></span><br><span class="line">            <span class="comment"># while regular sockets only have recv().</span></span><br><span class="line">            <span class="comment"># The recv() method blocks (at least in python 2.6) if it is</span></span><br><span class="line">            <span class="comment"># called when there is nothing to read, so we have to use</span></span><br><span class="line">            <span class="comment"># read() instead.</span></span><br><span class="line">            chunk = self.socket.read(self.read_chunk_size)</span><br><span class="line">        <span class="keyword">except</span> ssl.SSLError, e:</span><br><span class="line">            <span class="comment"># SSLError is a subclass of socket.error, so this except</span></span><br><span class="line">            <span class="comment"># block must come first.</span></span><br><span class="line">            <span class="keyword">if</span> e.args[<span class="number">0</span>] == ssl.SSL_ERROR_WANT_READ:</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="keyword">raise</span></span><br><span class="line">        <span class="keyword">except</span> socket.error, e:</span><br><span class="line">            <span class="keyword">if</span> e.args[<span class="number">0</span>] <span class="keyword">in</span> (errno.EWOULDBLOCK, errno.EAGAIN):</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="keyword">raise</span></span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> chunk:</span><br><span class="line">            self.close()</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">        <span class="keyword">return</span> chunk</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_merge_prefix</span><span class="params">(deque, size)</span>:</span></span><br><span class="line">    <span class="string">"""Replace the first entries in a deque of strings with a single</span></span><br><span class="line"><span class="string">    string of up to size bytes.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    &gt;&gt;&gt; d = collections.deque(['abc', 'de', 'fghi', 'j'])</span></span><br><span class="line"><span class="string">    &gt;&gt;&gt; _merge_prefix(d, 5); print d</span></span><br><span class="line"><span class="string">    deque(['abcde', 'fghi', 'j'])</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Strings will be split as necessary to reach the desired size.</span></span><br><span class="line"><span class="string">    &gt;&gt;&gt; _merge_prefix(d, 7); print d</span></span><br><span class="line"><span class="string">    deque(['abcdefg', 'hi', 'j'])</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    &gt;&gt;&gt; _merge_prefix(d, 3); print d</span></span><br><span class="line"><span class="string">    deque(['abc', 'defg', 'hi', 'j'])</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    &gt;&gt;&gt; _merge_prefix(d, 100); print d</span></span><br><span class="line"><span class="string">    deque(['abcdefghij'])</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    prefix = []</span><br><span class="line">    remaining = size</span><br><span class="line">    <span class="keyword">while</span> deque <span class="keyword">and</span> remaining &gt; <span class="number">0</span>:</span><br><span class="line">        chunk = deque.popleft()</span><br><span class="line">        <span class="keyword">if</span> len(chunk) &gt; remaining:</span><br><span class="line">            deque.appendleft(chunk[remaining:])</span><br><span class="line">            chunk = chunk[:remaining]</span><br><span class="line">        prefix.append(chunk)</span><br><span class="line">        remaining -= len(chunk)</span><br><span class="line">    deque.appendleft(<span class="string">''</span>.join(prefix))</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">doctests</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">import</span> doctest</span><br><span class="line">    <span class="keyword">return</span> doctest.DocTestSuite()</span><br></pre></td></tr></table></figure>

<h2 id="copyright"><a href="#copyright" class="headerlink" title="copyright"></a>copyright</h2><p>author：bigfish<br>copyright: <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">许可协议 知识共享署名 - 非商业性使用 4.0 国际许可协议</a></p>
<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/8" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/8</a></p>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/python/" rel="tag"># python</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2018/11/29/python-decorators/" rel="next" title="python decorators">
                <i class="fa fa-chevron-left"></i> python decorators
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2018/12/21/-tornado-yuan-ma-zhi-stackcontext%EF%BC%88-yi-%EF%BC%89/" rel="prev" title="tornado源码之StackContext（一）">
                tornado源码之StackContext（一） <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          
  
    <div id="gitalk-container"></div>
  


        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            Table of Contents
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            Overview
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">bigfish</p>
              <p class="site-description motion-element" itemprop="description">一些简单的想法</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/%7C%7C%20archive">
              
                  <span class="site-state-item-count">18</span>
                  <span class="site-state-item-name">posts</span>
                </a>
              </div>
            

            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/tags/index.html">
                  <span class="site-state-item-count">5</span>
                  <span class="site-state-item-name">tags</span>
                </a>
              </div>
            

          </nav>

          
            <div class="feed-link motion-element">
              <a href="/atom.xml" rel="alternate">
                <i class="fa fa-rss"></i>
                RSS
              </a>
            </div>
          

          <div class="links-of-author motion-element">
            
          </div>

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#iostream-py"><span class="nav-number">1.</span> <span class="nav-text">iostream.py</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#contents"><span class="nav-number">1.1.</span> <span class="nav-text">contents</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#example"><span class="nav-number">1.2.</span> <span class="nav-text">example</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#head"><span class="nav-number">1.3.</span> <span class="nav-text">head</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-init"><span class="nav-number">1.4.</span> <span class="nav-text">IOStream.__init__</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-connect"><span class="nav-number">1.5.</span> <span class="nav-text">IOStream.connect</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-read-until"><span class="nav-number">1.6.</span> <span class="nav-text">IOStream.read_until</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-read-bytes"><span class="nav-number">1.7.</span> <span class="nav-text">IOStream.read_bytes</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-write"><span class="nav-number">1.8.</span> <span class="nav-text">IOStream.write</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-close"><span class="nav-number">1.9.</span> <span class="nav-text">IOStream.close</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-handle-events"><span class="nav-number">1.10.</span> <span class="nav-text">IOStream._handle_events</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-run-callback"><span class="nav-number">1.11.</span> <span class="nav-text">IOStream._run_callback</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-run-callback-1"><span class="nav-number">1.12.</span> <span class="nav-text">IOStream._run_callback</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-read-from-socket"><span class="nav-number">1.13.</span> <span class="nav-text">IOStream._read_from_socket</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-read-to-buffer"><span class="nav-number">1.14.</span> <span class="nav-text">IOStream._read_to_buffer</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-read-from-buffer"><span class="nav-number">1.15.</span> <span class="nav-text">IOStream._read_from_buffer</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-handle-connect"><span class="nav-number">1.16.</span> <span class="nav-text">IOStream._handle_connect</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-handle-write"><span class="nav-number">1.17.</span> <span class="nav-text">IOStream._handle_write</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-consume"><span class="nav-number">1.18.</span> <span class="nav-text">IOStream._consume</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-add-io-state"><span class="nav-number">1.19.</span> <span class="nav-text">IOStream._add_io_state</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IOStream-read-buffer-size"><span class="nav-number">1.20.</span> <span class="nav-text">IOStream._read_buffer_size</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#copyright"><span class="nav-number">1.21.</span> <span class="nav-text">copyright</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">bigfish</span>

  
</div>


  <div class="powered-by">Powered by <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a></div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">Theme &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Pisces</a> v5.1.3</div>




<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>




        
<div class="busuanzi-count">
  <script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>

  
    <span class="site-uv">
      访客数
      <span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
      人
    </span>
  

  
    <span class="site-pv">
      总访问量
      <span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
      次
    </span>
  
</div>








        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.3"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.3"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.3"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.3"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.3"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.3"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.3"></script>



  


  




	





  





  








  <link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
  <script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>
  <div id="gitalk-container"></div>
  <script type="text/javascript">
    var gitalk = new Gitalk({
      clientID: '539ee569f1e8cf3ea34a',
      clientSecret: 'd4384d3c96e794fea423f52d48aec0caab7d0eea',
      repo: 'blog_comment',
      owner: 'TheBigFish',
      admin: ['TheBigFish'],
      id: location.pathname,
      distractionFreeMode: 'false'
    })
    gitalk.render('gitalk-container')
  </script>



  





  

  

  

  

  

  

</body>
</html>
